package jee.boot.module.iexp.task.impl;

import jee.boot.common.basic.BaseConfig;
import jee.boot.common.basic.Page;
import jee.boot.entity.system.Filter;
import jee.boot.common.properties.ProjectConfig;
import jee.boot.common.remote.RemoteEndpoint;
import jee.boot.common.standard.AccountHandler;
import jee.boot.common.standard.AuthorityHandler;
import jee.boot.common.standard.DocumentStorageClient;
import jee.boot.common.utils.StringUtils;
import jee.boot.entity.file.Attachment;
import jee.boot.module.iexp.config.ThreadPoolConfig;
import jee.boot.module.iexp.config.ThreadPoolConfigBig;
import jee.boot.entity.task.IexpTask;
import jee.boot.module.iexp.service.IexpTaskService;
import jee.boot.module.iexp.task.TaskListener;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class TaskExecute implements Runnable{
    private Logger logger = LoggerFactory.getLogger(TaskListener.class);
    /**
     * 线程池配置
     */
    private ThreadPoolConfig threadPoolConfig;

    /**
     * 线程池配置 用于大任务
     */
    private ThreadPoolConfigBig threadPoolConfigBig;
    /**
     * 线程池
     */
    private ThreadPoolExecutor threadPoolExecutor;

    private ThreadPoolExecutor threadPoolExecutorBig;
    /**
     * 任务服务
     */
    private IexpTaskService iexpTaskService;
    /**
     * 基础配置
     */
    private BaseConfig baseConfig;
    /**
     * 文件存储服务
     */
    private DocumentStorageClient fileService;
    /**
     * 当前登录用户的所有权限信息
     */
    private AuthorityHandler authorityHandler;
    /**
     * 当前账户信息
     */
    private AccountHandler accountHandler;
    /**
     * 远程访问
     */
    private RemoteEndpoint remoteEndpoint;
    /**
     * 项目配置
     */
    private ProjectConfig projectConfig;


    public TaskExecute(ThreadPoolConfig threadPoolConfig, ThreadPoolConfigBig threadPoolConfigBig, IexpTaskService iexpTaskService, BaseConfig baseConfig, DocumentStorageClient fileService, AuthorityHandler authorityHandler, AccountHandler accountHandler, RemoteEndpoint remoteEndpoint, ProjectConfig projectConfig) {
        this.threadPoolConfig = threadPoolConfig;
        this.threadPoolConfigBig = threadPoolConfigBig;
        this.iexpTaskService = iexpTaskService;
        this.baseConfig = baseConfig;
        this.fileService = fileService;
        this.authorityHandler=authorityHandler;
        this.accountHandler=accountHandler;
        this.remoteEndpoint=remoteEndpoint;
        this.projectConfig=projectConfig;
        initThreadPoolExecutor();
    }

    @Override
    public void run() {
        if (threadPoolConfig.getEnable()) {
            logger.info("启动iexp任务监听线程[" + Thread.currentThread().getId() + "]" + Thread.currentThread().getName());
            while (true) {
                this.taskFindHandler(threadPoolExecutorBig, "big");
                this.taskFindHandler(threadPoolExecutor, "normal");
                // 间隔休息
                try {
                    Thread.sleep(threadPoolConfig.getMonitorIntervalMillisecond());
                } catch (InterruptedException e) {
                    logger.warn("中断等待间隔,启动任务查询");
                    // 终止sleep
                }
            }
        }
    }

    private void taskFindHandler(ThreadPoolExecutor threadPoolExecutor, String bigOrNormal) {
        int free = 0;
        if (StringUtils.equalsIgnoreCase(bigOrNormal, "big")) {
            logger.info(String.format("%s,MaximumPoolSize:%s,ActiveCount:%s", "Big Thread:", threadPoolExecutor.getMaximumPoolSize(), threadPoolExecutor.getActiveCount()));
        } else {
            logger.info(String.format("%s,MaximumPoolSize:%s,ActiveCount:%s", "Normal Thread:", threadPoolExecutor.getMaximumPoolSize(), threadPoolExecutor.getActiveCount()));
        }
        free = threadPoolExecutor.getMaximumPoolSize() - threadPoolExecutor.getActiveCount();
        //如果当前线程的空闲线程数为零的话，不查询任务，直接返回
        if (free <= 0) {
            return;
        }
        //如果有当前空闲线程数，查出相应任务的数量，进入线程池，开始任务
        List<IexpTask> list = queryNewTask(bigOrNormal, free);
        for (IexpTask task : list) {
            runTask(task);
        }
    }

    /**
     * 执行任务
     *
     * @param task
     */
    private void runTask(IexpTask task) {
        // 检查并更新乐观锁,保证当前任务的独占性
        task.setIexpStatus("iexp_status_running");

        boolean update = checkAndUpdateVersionAndStatus(task);
        logger.info(String.format("update_status_value:%s,task id:%s,task name:%s", update, task.getId(), task.getName()));
        if (update) {
            // 任务类型: iexp_type_imp:导入;iexp_type_exp:导出;iexp_type_standard:标准后台任务
            switch (task.getIexpType()) {
                case "iexp_type_imp":
                    runImpTask(task);
                    break;
                case "iexp_type_exp":
                    runExpTask(task);
                    break;
                case "iexp_type_standard":
                    runStandardTask(task);
                    break;
                default:
                    logger.warn("不支持的任务类型[" + task.getIexpType() + "]");
            }

        } else {
            logger.warn("任务[" + task.getName() + "]已被其他服务独占,放弃执行");
        }
    }

    /**
     * 运行标准后台任务
     *
     * @param task
     */
    private void runStandardTask(IexpTask task) {
        //task.getBigOrNormal() 默认是false 如果设置成true就进入threadPoolExecutorBig线程池管理
        if ("big".equals(task.getBigOrNormal())) {
            logger.info(String.format("%s,MaximumPoolSize:%s,ActiveCount:%s,Task Que:%s,Task ID:%s", "StandardTask Big Thread:", threadPoolExecutorBig.getMaximumPoolSize(), threadPoolExecutorBig.getActiveCount(), threadPoolExecutorBig.getQueue().size(), task.getId()));
            threadPoolExecutorBig.execute(new StandardRunnable(task, iexpTaskService, fileService,authorityHandler,accountHandler,remoteEndpoint,projectConfig));
            logger.info(String.format("%s,MaximumPoolSize:%s,ActiveCount:%s,Task Que:%s,Task ID:%s", "StandardTask Big Thread:", threadPoolExecutorBig.getMaximumPoolSize(), threadPoolExecutorBig.getActiveCount(), threadPoolExecutorBig.getQueue().size(), task.getId()));
        } else {
            logger.info(String.format("%s,MaximumPoolSize:%s,ActiveCount:%s,Task Que:%s,Task ID:%s", "StandardTask Normal Thread:", threadPoolExecutor.getMaximumPoolSize(), threadPoolExecutor.getActiveCount(), threadPoolExecutor.getQueue().size(), task.getId()));
            threadPoolExecutor.execute(new StandardRunnable(task, iexpTaskService, fileService,authorityHandler,accountHandler,remoteEndpoint,projectConfig));
            logger.info(String.format("%s,MaximumPoolSize:%s,ActiveCount:%s,Task Que:%s,Task ID:%s", "StandardTask Normal Thread:", threadPoolExecutor.getMaximumPoolSize(), threadPoolExecutor.getActiveCount(), threadPoolExecutor.getQueue().size(), task.getId()));

        }
    }

    /**
     * 运行导出任务
     *
     * @param task
     */
    private void runExpTask(IexpTask task) {
        //task.getBigOrNormal() 默认是false 如果设置成true就进入threadPoolExecutorBig线程池管理
        if ("big".equals(task.getBigOrNormal())) {
            logger.info(String.format("%s,MaximumPoolSize:%s,ActiveCount:%s,Task Que:%s,Task ID:%s", "Exp Task Big Thread:", threadPoolExecutorBig.getMaximumPoolSize(), threadPoolExecutorBig.getActiveCount(), threadPoolExecutorBig.getQueue().size(), task.getId()));
            threadPoolExecutorBig.execute(new EmpRunnable(task, iexpTaskService, fileService,authorityHandler,accountHandler,remoteEndpoint,projectConfig));
            logger.info(String.format("%s,MaximumPoolSize:%s,ActiveCount:%s,Task Que:%s,Task ID:%s", "Exp Task Big Thread:", threadPoolExecutorBig.getMaximumPoolSize(), threadPoolExecutorBig.getActiveCount(), threadPoolExecutorBig.getQueue().size(), task.getId()));

        } else {
            logger.info(String.format("%s,MaximumPoolSize:%s,ActiveCount:%s,Task Que:%s,Task ID:%s", "StandardTask Normal Thread:", threadPoolExecutor.getMaximumPoolSize(), threadPoolExecutor.getActiveCount(), threadPoolExecutor.getQueue().size(), task.getId()));
            threadPoolExecutor.execute(new EmpRunnable(task, iexpTaskService, fileService,authorityHandler,accountHandler,remoteEndpoint,projectConfig));
            logger.info(String.format("%s,MaximumPoolSize:%s,ActiveCount:%s,Task Que:%s,Task ID:%s", "StandardTask Normal Thread:", threadPoolExecutor.getMaximumPoolSize(), threadPoolExecutor.getActiveCount(), threadPoolExecutor.getQueue().size(), task.getId()));

        }

    }

    /**
     * 运行导入任务
     *
     * @param task
     */
    private void runImpTask(IexpTask task) {
        //task.getBigOrNormal() 默认是false 如果设置成true就进入threadPoolExecutorBig线程池管理
        if ("big".equals(task.getBigOrNormal())) {
            logger.info(String.format("%s,MaximunPoolSize:%s,ActiveCount:%s,Task Que:%s,Task ID:%s", "Imp Task Big Thread:", threadPoolExecutorBig.getMaximumPoolSize(), threadPoolExecutorBig.getActiveCount(), threadPoolExecutorBig.getQueue().size(), task.getId()));
            threadPoolExecutorBig.execute(new ImpRunnable(task, iexpTaskService, fileService,authorityHandler,accountHandler,remoteEndpoint,projectConfig));
            logger.info(String.format("%s,MaximunPoolSize:%s,ActiveCount:%s,Task Que:%s,Task ID:%s", "Imp Task Big Thread:", threadPoolExecutorBig.getMaximumPoolSize(), threadPoolExecutorBig.getActiveCount(), threadPoolExecutorBig.getQueue().size(), task.getId()));
        } else {
            logger.info(String.format("%s,MaximunPoolSize:%s,ActiveCount:%s,Task Que:%s,Task ID:%s", "Imp Task Normal Thread:", threadPoolExecutor.getMaximumPoolSize(), threadPoolExecutor.getActiveCount(), threadPoolExecutor.getQueue().size(), task.getId()));
            threadPoolExecutor.execute(new ImpRunnable(task, iexpTaskService, fileService,authorityHandler,accountHandler,remoteEndpoint,projectConfig));
            logger.info(String.format("%s,MaximunPoolSize:%s,ActiveCount:%s,Task Que:%s,Task ID:%s", "Imp Task Normal Thread:", threadPoolExecutor.getMaximumPoolSize(), threadPoolExecutor.getActiveCount(), threadPoolExecutor.getQueue().size(), task.getId()));
        }
    }

    /**
     * 检查并更新乐观锁,保证当前任务的独占性
     *
     * @param task
     * @return
     */
    private boolean checkAndUpdateVersionAndStatus(IexpTask task) {
        task.setVersion(task.getVersion() + 1);
        return iexpTaskService.checkAndUpdateVersionAndStatus(task);
    }

    /**
     * 查询New状态的任务
     *
     * @return
     */
    private List<IexpTask> queryNewTask(String bigOrNormal, int free) {
        IexpTask query = new IexpTask();
        //如果只监控自己机器的任务,添加过滤条件
        if (threadPoolConfig.getMonitorMyselfTask()) {
            String hostName = "defaultHostName";
            try {
                hostName = InetAddress.getLocalHost().getHostName();
            } catch (Exception e) {
            }
            query.addFilter(new Filter("computerName", "=", hostName));
        }

        // 监控新建状态的任务
        query.addFilter(new Filter("iexpStatus", "=", "iexp_status_new"));
        // 监控BIG OR NORMAL 状态的任务
        query.addFilter(new Filter("bigOrNormal", "=", bigOrNormal));
        // 设置limit 限制
        query.setPage(new Page<>(1,free));
        return iexpTaskService.findPage(query).getList();
    }

    /**
     * 初始化线程池
     */
    private void initThreadPoolExecutor() {
        threadPoolExecutor = new ThreadPoolExecutor(
                threadPoolConfig.getCorePoolSize(),
                threadPoolConfig.getMaxPoolSize(),
                5,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(threadPoolConfig.getQueueCapacity()), // 使用有界队列，避免OOM
                new ThreadPoolExecutor.DiscardPolicy());
        threadPoolExecutor.allowCoreThreadTimeOut(true);
        threadPoolExecutor.setThreadFactory(new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                return new Thread(r, "thread_pool_" + r.hashCode());
            }
        });

        threadPoolExecutorBig = new ThreadPoolExecutor(
                threadPoolConfigBig.getCorePoolSize(),
                threadPoolConfigBig.getMaxPoolSize(),
                5,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(threadPoolConfigBig.getQueueCapacity()), // 使用有界队列，避免OOM
                new ThreadPoolExecutor.DiscardPolicy());
        threadPoolExecutorBig.allowCoreThreadTimeOut(true);
        threadPoolExecutorBig.setThreadFactory(new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                return new Thread(r, "thread_pool_big_" + r.hashCode());
            }
        });
    }


    public static void main1(String[] args) {
        File file = new File("C:\\data\\test.zip");
        ZipOutputStream out = null;
        try {
            out = new ZipOutputStream(new FileOutputStream(file));
            for (int i = 0; i < 2; i++) {
                // 添加到zip
                out.putNextEntry(new ZipEntry(i + "文件.txt"));
                IOUtils.write("测试文件内容" + i, out, "UTF-8");
                out.closeEntry();
            }
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        Thread thread = null;
        List<Thread> tempList = new ArrayList<>();
        while (true) {
            if (thread == null || !thread.isAlive()) {
                System.out.println((thread == null ? "启动" : "重启") + "监听线程,开始监听任务");
                thread = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                                5,
                                5,
                                1,
                                TimeUnit.SECONDS,
                                new ArrayBlockingQueue<>(100), // 使用有界队列，避免OOM
                                new ThreadPoolExecutor.DiscardPolicy());
                        threadPoolExecutor.allowCoreThreadTimeOut(true);
                        threadPoolExecutor.setThreadFactory(new ThreadFactory() {
                            @Override
                            public Thread newThread(Runnable r) {
                                return new Thread(r, "thread_pool_" + r.hashCode());
                            }
                        });
                        Scanner sc = new Scanner(System.in);
                        for (; ; ) {
                            System.out.print("请输入下一个数据（直接回车结束输入）：");
                            String s = sc.nextLine();
                            if (s.equals("exit")) {
                                System.out.println("已结束输入！");
                                break;
                            }
                            if (StringUtils.isNotBlank(s)) {
                                Thread trun = new Thread(new Runnable() {
                                    @Override
                                    public void run() {
                                        System.out.println(Thread.currentThread().getName() + "-开始任务:" + s);
                                        try {
                                            Thread.sleep(10 * 1000);
                                        } catch (InterruptedException e) {
                                            e.printStackTrace();
                                        }
                                        int size = 1000000;
                                        List<Attachment> list = new ArrayList<>();
                                        System.out.println(Thread.currentThread().getName() + "开始写入数据:" + (size / 10000) + "万");
                                        for (int i = 0; i < size; i++) {
                                            if (i % 100000 == 0) {
                                                System.out.println(Thread.currentThread().getName() + "已写入" + (i / 10000) + "万数据");
                                            }
                                            list.add(new Attachment("id1111111111111111111111111111111111111111111111112222222222222222222223333333333333333333444444444444555555555566666666667777777777888888888888888888" + i));
                                        }

                                        System.out.println(Thread.currentThread().getName() + "-结束任务:" + s);
                                    }
                                });
                                tempList.add(trun);
                                threadPoolExecutor.execute(trun);
                                trun = null;
                            }
                            System.gc();
                            System.out.println(
                                    "线程池中线程数目:" + threadPoolExecutor.getPoolSize() +
                                            ",队列中等待执行的任务数目:" + threadPoolExecutor.getQueue().size() +
                                            ",已执行完的任务数目:" + threadPoolExecutor.getCompletedTaskCount() +
                                            ",活跃线程数:" + threadPoolExecutor.getActiveCount() +
                                            ",空闲线程数:" + (threadPoolExecutor.getMaximumPoolSize() - threadPoolExecutor.getActiveCount()));
//                            for (Thread t : tempList) {
//                                if (!t.isAlive()) {
//                                    t.isInterrupted();
//                                }
//                                try {
//
//                                    Field f = threadPoolExecutor.getClass().getDeclaredField("workers");
//                                    f.setAccessible(true);
//                                    Object o = f.get(threadPoolExecutor);
//                                    System.out.println(o);
//
//
//                                    HashSet<Object> workers = (HashSet<Object>) o;
//                                    for (Object work : workers) {
//                                        System.out.println("work : " + work);
//                                    }
//
//                                } catch (Exception e) {
//                                    e.printStackTrace();
//                                }
//                            }

                        }


                    }

                });
                thread.setDaemon(true);
                thread.start();
            }
            try {
                Thread.sleep(10000);

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

    public static void main2(String[] args) {
        final List<Attachment> list1 = new ArrayList<>();
//        List<SysAttachment> list2=new ArrayList<>();

        Attachment zhangsan = new Attachment("zhangsan");
        list1.add(zhangsan);
        System.out.println(list1);//
        zhangsan.setId("99999");
        System.out.println(list1);
        zhangsan = null;
        System.out.println(list1);
    }


}
